package imgo

import (
	"fmt"
	"gitee.com/squbirreland/imgo/utils/logger"
	"gitee.com/squbirreland/imgo/utils/try"
	"net"
	"sync"
	"time"
)

// Logger logger
var Logger *logger.Logger

//globalIn 全局消息队列
var globalIn chan *Message

//globalClose 全局链接关闭队列
var globalClose = make(chan *net.Conn, 64)

//全局端口监听对象
type connector struct {
	listenPort  int
	listener    net.Listener
	centers     []*Center
	iWorker     IWorkRoutine
	iManagement IManagement
	config      *Configuration
}

// Listen 开启监听
func Listen(listenPort int) *connector {
	listen, err := net.Listen("tcp", fmt.Sprintf(":%d", listenPort))
	try.Throw(err)
	return &connector{
		listenPort: listenPort,
		listener:   listen,
	}
}

// Config 进行设置
func (c *connector) Config(config *Configuration) *connector {
	if config.GlobalMessageChannelLength == 0 {
		config.GlobalMessageChannelLength = 2048
	}
	if config.MonitorPrintDelay == 0 {
		config.MonitorPrintDelay = 10 * 1000 * 1000 * 1000
	}
	c.config = config
	return c
}

// Run 启动程序
func (c *connector) Run(iManagement IManagement, worker IWorkRoutine, centers ...*Center) {
	//默认配置
	if c.config == nil {
		c.config = &Configuration{
			GlobalMessageChannelLength: 2048,
			LogToFile:                  false,
			MonitorPrintDelay:          10 * 1000 * 1000 * 1000,
		}
	}
	//赋值并初始化全局
	c.centers = centers
	c.iWorker = worker
	c.iManagement = iManagement
	globalIn = make(chan *Message, c.config.GlobalMessageChannelLength)
	Logger = logger.NewLoggerFactory(c.config.LogToFile, c.config.LogFilePath).GetLogger()
	//正式启动
	//开启全局消息队列和关闭队列处理
	go c.handleIn()
	go c.handleClose()
	//开启全局监控
	go c.monitor()
	Logger.Info().Println(" -- init success and starting listen ", c.listenPort, " --")
	//开始tcp链接监听
	go c.connectListener()
}

//connectListener 链接驱动主携程
func (c *connector) connectListener() {
	defer func() {
		e := recover()
		if e != nil {
			Logger.Err().Println(e)
		}
		err := c.listener.Close()
		if err != nil {
			Logger.Err().Println(err.Error())
		}
		Logger.Info().Println(" -- listener ", c.listenPort, " closed -- ")
	}()

	i := 0
	for {
		//获取到链接
		connection, err := c.listener.Accept()
		try.Catch(err)
		//执行新连接拦截方法
		conn := IManagement.NewConnInterceptor(c.iManagement, &connection)
		if conn == nil {
			continue
		}
		//新建worker
		var lock sync.Mutex
		worker := &WorkRoutine{
			Conn:       conn,
			ChanIn:     make(chan *[]byte, 1024),
			ChanOut:    make(chan *[]byte, 1024),
			Exit:       (c.centers)[i].chanExit,
			ConnLocker: &lock,
		}
		//对worker执行拦截
		worker = IManagement.NewWorkerInterceptor(c.iManagement, worker)
		if worker == nil || worker.Conn == nil {
			continue
		}
		//拷贝IWorker并分发至center进行启动
		iWorker := c.iWorker.Copy()
		go (c.centers)[i].distribute(iWorker, worker)
		i++
		if i == len(c.centers) {
			i = 0
		}
	}
}

// handleIn globalIn 的处理器
//由 connector 核心开启携程
func (c *connector) handleIn() {
	for {
		msg := <-globalIn
		//新建携程 进行消息解析与分发
		go c.msgHandler(msg)
	}
}

// handleClose globalClose 的处理器
//由 connector 核心开启携程
func (c *connector) handleClose() {
	for {
		needClose := <-globalClose
		go IManagement.ConnCloser(c.iManagement, needClose)
	}
}

// msgHandler 消息解析与分发
func (c *connector) msgHandler(message *Message) {
	//执行 IManagement 接口的 Parse 解析消息 默认flag=0
	to, msg := IManagement.Parse(c.iManagement, message.From, message.OriginMsg, 0)
	if to == nil || len(to) == 0 || msg == nil {
		return
	}
	//遍历所有管理器
	for i := range c.centers {
		//对管理器中的map进行读锁遍历找到需求的出口 并发送消息
		(c.centers)[i].mapUsed.RLock()
		for j := range to {
			r := (c.centers)[i].routineMap[to[j]]
			if r != nil {
				r.ChanOut <- msg
			}
		}
		(c.centers)[i].mapUsed.RUnlock()
	}
}

// monitor 全局信息监控
func (c *connector) monitor() {
	ticker := time.NewTicker(time.Duration(c.config.MonitorPrintDelay))
	for range ticker.C {
		s := fmt.Sprintf(" -- monitor -len(globalIn):%d ", len(globalIn))
		for i := range c.centers {
			size := len((c.centers)[i].routineMap)
			s += fmt.Sprintf(" m%d:%d", i, size)
		}
		Logger.Info().Println(s)
	}
}
